// DisplayReZ.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <windows.h>
#include <conio.h>
#include <stdarg.h>

#include "..\ReZlib/DisplayDeviceMngr.h"

typedef std::wstring WSTRING;

#define MAX_DEVICE_NAME_   (32+1)

void DebugPrinter(WSTRING &outBuffer, const WCHAR* format, ...)
{
   WCHAR *buffer = NULL;
   int buffSize = 0; 
   va_list  args;
   va_start(args, format);

   buffSize = _vscwprintf(format, args);
   buffer = (WCHAR*)malloc((++buffSize) * sizeof(WCHAR));
   _ASSERT(buffer);
   vswprintf(buffer, buffSize, format, args);
   va_end(args);

   buffer[buffSize-1] = L'\0';   // terminator
   outBuffer = buffer;
   free(buffer);
}

#define DEBUG_PRINT(fmt,...)      {WSTRING wBuff; DebugPrinter(wBuff, fmt, __VA_ARGS__); wprintf(wBuff.c_str()); }

void DescribeDisplay(const WCHAR *pDeviceName, DWORD flags)
{
   BOOL ret = FALSE;
   DEVMODE  deviceMode;
   DWORD index;
   
   ZeroMemory(&deviceMode, sizeof(DEVMODE));
   deviceMode.dmSize = sizeof(DEVMODE);
   deviceMode.dmDriverExtra =0;

   // get the current mode.
   index = ENUM_CURRENT_SETTINGS;
   ret = EnumDisplaySettings(pDeviceName, index, &deviceMode);
   DEBUG_PRINT(L"Display: '%s' \n", pDeviceName);
   DEBUG_PRINT(L"   width %d x", deviceMode.dmPelsWidth);
   DEBUG_PRINT(L"   height %d\n", deviceMode.dmPelsHeight);
   DEBUG_PRINT(L"   bpp %d      ", deviceMode.dmBitsPerPel);
   DEBUG_PRINT(L"   freq. %d    ", deviceMode.dmDisplayFrequency);
   DEBUG_PRINT(L"   flags %d\n", deviceMode.dmDisplayFlags);
   DEBUG_PRINT(L"   positn (x,y) (%d,%d) ", deviceMode.dmPosition.x, deviceMode.dmPosition.y);

   DEBUG_PRINT(L"\n");
}

BOOL ControlDisplay(const WCHAR *pPrimaryName, const WCHAR *pDeviceName, BOOL enable)
{
   DEVMODE  DevMode, DevModePrimary; 
   LONG     result;
   BOOL     ret;

   ZeroMemory(&DevMode, sizeof(DevMode));
   DevMode.dmSize = sizeof(DevMode);
   if (enable)
   {
      ZeroMemory(&DevModePrimary, sizeof(DevModePrimary));
      DevModePrimary.dmSize = sizeof(DevModePrimary);

      ret = EnumDisplaySettings(pPrimaryName, ENUM_REGISTRY_SETTINGS, &DevModePrimary);      

      // enable it again
      DevMode.dmPelsWidth = DevModePrimary.dmPelsWidth;
      DevMode.dmPelsHeight = DevModePrimary.dmPelsHeight;
      DevMode.dmPosition.x = DevModePrimary.dmPelsWidth;
      DevMode.dmPosition.y = 0;
      DevMode.dmDisplayFrequency = DevModePrimary.dmDisplayFrequency;
      DevMode.dmBitsPerPel = DevModePrimary.dmBitsPerPel;
      DevMode.dmSpecVersion = DM_SPECVERSION;
      DevMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_POSITION
                  | DM_DISPLAYFREQUENCY ;//| DM_DISPLAYFLAGS ;
   }
   else
   {
      DevMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_POSITION
                   | DM_DISPLAYFLAGS ;
      //disable
      DevMode.dmPelsWidth = 0;
      DevMode.dmPelsHeight = 0;
      DevMode.dmPosition.x = 0;
      DevMode.dmPosition.y = 0;
   }

   result = ChangeDisplaySettingsEx(pDeviceName, 
                                   &DevMode,
                                   NULL,
                                   (enable?CDS_NORESET:0) | CDS_UPDATEREGISTRY,//
                                   NULL);
   if (0!=result)
   {
      DEBUG_PRINT(L"\nChange Display Settings display '%s' failed with code:%s.\n", pDeviceName, CDisplayDeviceManager::ChangeSettingsError(result));
      return(FALSE);
   }
   result = ChangeDisplaySettings( NULL, 0);
   if (0!=result)
   {
      DEBUG_PRINT(L"\nSave Display Settings display '%s' failed with code:%s.\n", pDeviceName, CDisplayDeviceManager::ChangeSettingsError(result));
      return(FALSE);
   }
   return(TRUE);
}


int _tmain(int argc, _TCHAR* argv[])
{
   DISPLAY_DEVICE device;
   WCHAR primaryDevName[MAX_DEVICE_NAME_];
   DWORD index=0;

   ZeroMemory(&device, sizeof(DISPLAY_DEVICE));
   device.cb = sizeof(DISPLAY_DEVICE);
   BOOL ret = TRUE; 
   while(ret)
   {
      ret = EnumDisplayDevices(0, index, &device, EDD_GET_DEVICE_INTERFACE_NAME );
      if (ret)
      {
         if ((device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) &&
            (device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE))
         {
            wcsncpy(primaryDevName, device.DeviceName, MAX_DEVICE_NAME_ -1);
            primaryDevName[MAX_DEVICE_NAME_ -1] = L'\0'; // null terminator
         }

         if (((device.StateFlags & DISPLAY_DEVICE_ACTIVE) || (device.StateFlags & DISPLAY_DEVICE_MODESPRUNED) || 
             (device.StateFlags == 0)  // device disabled
              ) && 
             (~(device.StateFlags ^ DISPLAY_DEVICE_MIRRORING_DRIVER)))
         {
            DEBUG_PRINT(L"Device %ld = '%s' [%s] %p...", index, device.DeviceName, device.DeviceString, device.StateFlags);
            if (device.StateFlags & DISPLAY_DEVICE_ACTIVE)              DEBUG_PRINT (L"Active ");
            if (device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) DEBUG_PRINT (L"Attached ");
            if (device.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER)    DEBUG_PRINT (L"Mirror ");
            if (device.StateFlags & DISPLAY_DEVICE_MODESPRUNED)         DEBUG_PRINT (L"Pruned ");
            if (device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)      DEBUG_PRINT (L"Prim. ");
            if (device.StateFlags & DISPLAY_DEVICE_REMOVABLE)           DEBUG_PRINT (L"Removable ");
            if (device.StateFlags & DISPLAY_DEVICE_VGA_COMPATIBLE)      DEBUG_PRINT (L"VGA-capable ");
            if (device.StateFlags & DISPLAY_DEVICE_DISCONNECT)          DEBUG_PRINT (L"disconnected ");
            DEBUG_PRINT(L"\n");

            DescribeDisplay(device.DeviceName, device.StateFlags);
         }
      }
      index++;
   }

   if (argc>=3)
   {
      if (0==wcscmp(argv[2], L"-enable"))
      {
         ControlDisplay(primaryDevName, argv[1], TRUE);
      }
      if (0==wcscmp(argv[2], L"-disable"))
      {
         ControlDisplay(primaryDevName, argv[1], FALSE);
      }
   }
	return 0;
}

